# app/main.py
import os
import sys
import secrets
import functools
import hashlib
import logging
import time
from flask import Flask, request, render_template, jsonify, g
from dotenv import load_dotenv

# 添加项目根目录到 Python 路径，解决导入问题
current_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(current_dir)
if project_root not in sys.path:
    sys.path.insert(0, project_root)

# 确定项目的根目录
# 通常 __file__ 指向当前文件 main.py
# os.path.dirname(__file__) 是 app/ 目录
# os.path.dirname(os.path.dirname(__file__)) 是项目根目录 parse-smart-address/
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# 在创建 Flask 应用之前加载 .env 文件
# 指定 .env 文件的路径为项目根目录下的 .env
dotenv_path = os.path.join(project_root, '.env')
load_dotenv(dotenv_path=dotenv_path)

# 导入日志配置
from app.core.logging_config import setup_logging

# 创建 Flask 应用实例
# 指定模板文件夹相对于当前文件 main.py 的路径
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
static_dir = os.path.join(os.path.dirname(__file__), 'static')

# 检查是否禁用Web UI来决定是否包含模板和静态文件
disable_web_ui = os.getenv("DISABLE_WEB_UI", "false").lower() in ["true", "1", "yes", "on"]
if disable_web_ui:
    app = Flask(__name__)
else:
    app = Flask(__name__, template_folder=template_dir, static_folder=static_dir)

# 初始化日志
logger = setup_logging()

# 初始化解析器变量
address_parser = None

# 检查是否禁用Web UI
DISABLE_WEB_UI = disable_web_ui
if DISABLE_WEB_UI:
    print("Web UI已禁用，仅提供API接口")
    logger.info("Web UI已禁用，仅提供API接口")
else:
    print("Web UI已启用")
    logger.info("Web UI已启用")

# --- 配置API认证 ---
# 从环境变量获取API Key，如果不存在则生成一个随机密钥
API_KEY = os.getenv("API_KEY")
if not API_KEY:
    # 生成一个16字节的随机字符串作为默认API密钥
    API_KEY = secrets.token_hex(16)
    print(f"警告: 未设置API_KEY环境变量，已自动生成临时密钥: {API_KEY}")
    print("建议在.env文件中设置固定的API_KEY以提高安全性")
    logger.warning("未设置API_KEY环境变量，已自动生成临时密钥")
else:
    print(f"API认证已启用，使用环境变量中的API_KEY")
    logger.info("API认证已启用，使用环境变量中的API_KEY")

# 允许的API密钥集合（支持多个密钥）
ALLOWED_API_KEYS = set()
ALLOWED_API_KEYS.add(API_KEY)

# 从环境变量中读取额外的API密钥（如果有的话，用逗号分隔）
extra_keys = os.getenv("EXTRA_API_KEYS", "")
if extra_keys:
    for key in extra_keys.split(','):
        key = key.strip()
        if key:
            ALLOWED_API_KEYS.add(key)
    print(f"已加载 {len(ALLOWED_API_KEYS)} 个API密钥")
    logger.info(f"已加载 {len(ALLOWED_API_KEYS)} 个API密钥")

# --- 请求前后处理中间件 ---
@app.before_request
def before_request():
    """请求前处理"""
    # 设置请求开始时间，用于计算处理时间
    g.request_start_time = time.time()
    # 记录请求信息
    logger.info(f"收到请求: {request.method} {request.path} [来源: {request.remote_addr}]")

@app.after_request
def after_request(response):
    """请求后处理"""
    # 计算请求处理时间
    if hasattr(g, 'request_start_time'):
        elapsed = time.time() - g.request_start_time
        logger.info(f"请求处理完成: {request.method} {request.path} - 状态码: {response.status_code} - 耗时: {elapsed:.4f}秒")
    return response

@app.errorhandler(Exception)
def handle_exception(e):
    """全局异常处理"""
    logger.error(f"未处理的异常: {str(e)}", exc_info=True)
    return jsonify({"error": "服务器内部错误"}), 500

# --- API认证装饰器 ---
def require_api_key(view_function):
    @functools.wraps(view_function)
    def decorated_function(*args, **kwargs):
        # 从请求头获取API Key
        api_key = request.headers.get('X-API-Key')
        
        # 如果没有在header中找到，尝试从查询参数中获取
        if not api_key:
            api_key = request.args.get('api_key')
            
        # 如果仍然没有找到，尝试从JSON主体中获取
        if not api_key and request.is_json:
            json_data = request.get_json(silent=True)
            if json_data and isinstance(json_data, dict):
                api_key = json_data.get('api_key')
        
        # 验证API Key
        if not api_key or api_key not in ALLOWED_API_KEYS:
            logger.warning(f"API认证失败: 无效的API密钥 [IP: {request.remote_addr}]")
            return jsonify({"error": "无效的API密钥，请提供有效的X-API-Key请求头"}), 401
        
        logger.debug(f"API认证成功 [IP: {request.remote_addr}]")
        return view_function(*args, **kwargs)
    return decorated_function

# --- 导入核心解析器 ---
try:
    from app.core.parser import get_parser
    # 初始化解析器实例
    address_parser = get_parser()
    if address_parser:
        print("地址解析器初始化成功")
        logger.info("地址解析器初始化成功")
    else:
        print("警告: 地址解析器初始化返回 None")
        logger.warning("地址解析器初始化返回 None")
except Exception as e:
    print(f"初始化地址解析器时发生错误: {e}")
    logger.error(f"初始化地址解析器时发生错误: {e}", exc_info=True)
    address_parser = None

# --- Web UI 路由 ---
@app.route('/', methods=['GET', 'POST'])
def index():
    """
    处理 Web 界面的 GET 和 POST 请求。
    GET: 显示地址输入表单。
    POST:接收表单提交的地址，调用解析器，并显示结果。
    """
    # 如果Web UI被禁用，返回提示信息
    if DISABLE_WEB_UI:
        logger.info(f"尝试访问已禁用的Web UI [IP: {request.remote_addr}]")
        return jsonify({
            "error": "Web UI已禁用",
            "message": "此服务已配置为仅提供API接口，请使用 /api/parse 接口进行地址解析",
            "api_info": "访问 /api/info 获取API使用说明"
        }), 403
    
    result = None
    error = None
    address_input = ""

    if not address_parser:
        error = "地址解析服务当前不可用，请检查配置。"
        logger.error("访问首页时发现解析器不可用")
        return render_template('index.html', error=error)

    if request.method == 'POST':
        address_input = request.form.get('address', '').strip()
        if address_input:
            try:
                # 记录解析请求（注意不记录完整地址，避免泄露敏感信息）
                address_preview = address_input[:15] + "..." if len(address_input) > 15 else address_input
                logger.info(f"Web界面请求解析地址: {address_preview}")
                
                # 调用核心解析逻辑
                parsed_data = address_parser.parse(address_input)
                if "error" in parsed_data:
                    error = parsed_data["error"]
                    logger.warning(f"地址解析失败: {error}")
                else:
                    # 格式化 JSON 以便在 HTML 中美观显示
                    import json
                    result = json.dumps(parsed_data, indent=4, ensure_ascii=False)
                    logger.info("地址解析成功")
            except Exception as e:
                print(f"处理 / 请求时发生错误: {e}")
                error = f"解析过程中发生内部错误: {str(e)}"
                logger.error(f"处理Web请求时发生错误: {str(e)}", exc_info=True)
        else:
            error = "请输入要解析的地址。"
            logger.warning("用户提交了空地址")

    # 渲染 index.html 模板，并传递结果或错误信息
    return render_template('index.html', result=result, error=error, address_input=address_input)

# --- API Endpoint 路由 ---
@app.route('/api/parse', methods=['POST'])
@require_api_key  # 添加API Key认证
def api_parse_address():
    """
    处理 API 请求，接收 JSON 格式的地址，返回 JSON 格式的解析结果。
    需要有效的API Key才能访问此端点。
    """
    if not address_parser:
        logger.error("API请求时发现解析器不可用")
        return jsonify({"error": "地址解析服务当前不可用，请检查配置。"}), 503 # Service Unavailable

    if not request.is_json:
        logger.warning("API请求格式错误: 非JSON格式请求")
        return jsonify({"error": "请求必须是 JSON 格式"}), 400 # Bad Request

    data = request.get_json()
    address = data.get('address', '').strip()

    if not address:
        logger.warning("API请求缺少address字段或为空")
        return jsonify({"error": "缺少 'address' 字段或地址为空"}), 400 # Bad Request

    try:
        # 记录解析请求（不记录完整地址，避免泄露敏感信息）
        address_preview = address[:15] + "..." if len(address) > 15 else address
        logger.info(f"API请求解析地址: {address_preview}")
        
        # 调用核心解析逻辑
        parsed_data = address_parser.parse(address)
        if "error" in parsed_data:
             # 根据错误类型返回不同的状态码可能更合适，但为简单起见，这里统一返回 500 或根据 AI 错误返回特定代码
             status_code = 500 # Internal Server Error or specific error
             if "AI 服务请求频率超限" in parsed_data["error"]:
                 status_code = 429 # Too Many Requests
                 logger.warning(f"API请求失败: AI服务请求频率超限")
             elif "无法连接到 AI 服务" in parsed_data["error"]:
                 status_code = 503 # Service Unavailable
                 logger.error(f"API请求失败: 无法连接到AI服务")
             else:
                 logger.error(f"API请求失败: {parsed_data['error']}")
             return jsonify(parsed_data), status_code
        else:
             logger.info("API地址解析成功")
             return jsonify(parsed_data), 200 # OK

    except Exception as e:
        print(f"处理 /api/parse 请求时发生错误: {e}")
        logger.error(f"处理API请求时发生未处理的异常: {str(e)}", exc_info=True)
        return jsonify({"error": f"处理请求时发生内部错误: {str(e)}"}), 500 # Internal Server Error

# --- API信息端点 --- 
@app.route('/api/info', methods=['GET'])
def api_info():
    """
    提供API使用信息，包括如何进行认证等
    """
    logger.info("访问API信息页面")
    info = {
        "name": "智能地址解析API",
        "version": "1.0",
        "description": "智能解析中文地址信息为结构化数据",
        "auth": "需要在请求头中提供X-API-Key",
        "endpoints": [
            {
                "path": "/api/parse",
                "method": "POST",
                "description": "解析地址",
                "body_format": {"address": "要解析的地址文本"},
                "returns": "结构化的地址信息JSON"
            },
            {
                "path": "/api/info",
                "method": "GET",
                "description": "获取API信息",
                "auth_required": False
            }
        ],
        "authentication": {
            "method": "API Key",
            "header": "X-API-Key",
            "alternate_methods": [
                "URL参数: ?api_key=YOUR_API_KEY",
                "请求体中包含 api_key 字段"
            ]
        }
    }
    return jsonify(info)

# --- API密钥生成工具 ---
@app.route('/api/generate-key', methods=['GET'])
def generate_api_key():
    """
    生成一个新的API密钥(开发环境使用，生产环境应该禁用或添加管理员认证)
    """
    # 检查是否为开发环境
    if os.getenv("APP_ENV") != "development" and os.getenv("FLASK_ENV") != "development":
        logger.warning(f"在生产环境尝试访问API密钥生成端点 [IP: {request.remote_addr}]")
        return jsonify({"error": "此功能仅在开发环境中可用"}), 403

    # 生成一个新的API密钥
    new_key = secrets.token_hex(16)
    
    # 在内存中添加此密钥(临时有效)
    ALLOWED_API_KEYS.add(new_key)
    
    logger.info(f"生成了新的API密钥 [IP: {request.remote_addr}]")
    return jsonify({
        "message": "新API密钥已生成",
        "api_key": new_key,
        "note": "此密钥仅在本次服务运行期间有效，重启后将失效。请考虑将其添加到.env文件的EXTRA_API_KEYS中使其永久有效。"
    })

# --- API文档页面 ---
@app.route('/api/docs', methods=['GET'])
def api_docs():
    """
    提供API文档页面，包含详细的使用说明和示例
    """
    # 如果Web UI被禁用，返回JSON格式的API文档
    if DISABLE_WEB_UI:
        logger.info(f"尝试访问已禁用的API文档页面 [IP: {request.remote_addr}]")
        return jsonify({
            "error": "API文档页面已禁用",
            "message": "此服务已配置为仅提供API接口，请使用 /api/info 获取API使用说明",
            "api_info": "访问 /api/info 获取API使用说明"
        }), 403
    
    logger.info("访问API文档页面")
    return render_template('api_docs.html')

# --- 应用启动入口 ---
if __name__ == '__main__':
    # 从环境变量获取端口，默认为 5000
    port = int(os.environ.get('PORT', 5000))
    
    # 确定运行环境
    env = os.getenv("APP_ENV", "production").lower()
    debug_mode = env in ["development", "dev", "debug"]
    
    if debug_mode:
        print(f"运行环境: 开发模式 (debug={debug_mode})")
        logger.info(f"以开发模式启动服务器，debug={debug_mode}")
    else:
        print(f"运行环境: 生产模式")
        logger.info("以生产模式启动服务器")
    
    # 启动 Flask 开发服务器
    # debug=True 会在代码更改时自动重启服务器，但在生产环境中应设为 False
    # host='0.0.0.0' 使服务可以从本地网络访问 (例如 Docker 容器)
    logger.info(f"服务器启动，监听地址: 0.0.0.0:{port}")
    app.run(host='0.0.0.0', port=port, debug=debug_mode) 